package com.atguigu.tingshu.payment.service.impl;

import com.atguigu.tingshu.account.client.impl.RechargeInfoDegradeFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.account.RechargeInfo;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.order.client.OrderInfoFeignClient;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private WxPayV3Config wxPayV3Config;

    @Autowired
    private RSAAutoCertificateConfig config;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;

    @Autowired
    private RechargeInfoDegradeFeignClient rechargeInfoDegradeFeignClient;

    /**
     * 微信支付
     *
     * @param paymentType
     * @param orderNo
     * @param userId
     * @return
     */
    @Override
    public Map<String, Object> createJsapi(String paymentType, String orderNo, Long userId) {
        // 创建map集合
        Map<String, Object> result = new HashMap<>();
        //  记录交易记录，方便后续对账 payment_info
        //  声明一个变量存储交易记录金额
        BigDecimal paymentAmount = new BigDecimal("0.00");
        if (paymentType.equals(SystemConstant.PAYMENT_TYPE_ORDER)) {
            Result<OrderInfo> orderInfoResult = orderInfoFeignClient.getOrderInfo(orderNo);
            Assert.notNull(orderInfoResult, "订单信息为空");
            OrderInfo orderInfo = orderInfoResult.getData();
            Assert.notNull(orderInfo, "订单信息为空");
            // 判断当前这个订单状态,如果这个订单已取消了，则不能再次点击支付
            if (SystemConstant.ORDER_STATUS_CANCEL.equals(orderInfo.getOrderStatus())) {
                result.put("code", "999");
                result.put("message", "订单已取消");
                return result;
            }
            paymentAmount = orderInfo.getOrderAmount();
        } else {
            // 充值：recharge_info.recharge_amount
            Result<RechargeInfo> rechargeInfoResult = rechargeInfoDegradeFeignClient.getRechargeInfo(orderNo);
            Assert.notNull(rechargeInfoResult, "充值订单信息为空");
            RechargeInfo rechargeInfo = rechargeInfoResult.getData();
            Assert.notNull(rechargeInfo, "充值订单信息为空");
            paymentAmount = rechargeInfo.getRechargeAmount();
        }
        // 保存支付交易记录
        paymentInfoService.savePaymentInfo(userId, paymentType, orderNo, paymentAmount);
        // 创建service 对象
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();

        //
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(1);
        request.setAmount(amount);
        request.setAppid(wxPayV3Config.getAppid());
        request.setDescription("测试商品标题");
        request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
        request.setOutTradeNo(orderNo);
        // 给设置一个过期时间：等于取消订单时间
        // request.setTimeExpire();
        // 创建payer对象
        Payer payer = new Payer();
        // 远程调用，获取用户openid
        Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfoVo(userId);
        Assert.notNull(userInfoVoResult, "用户信息结果集为空");
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        Assert.notNull(userInfoVo, "用户信息为空");
        payer.setOpenid(userInfoVo.getWxOpenId());
        // 设置支付者
        request.setPayer(payer);
        // response包含了调起支付所需的所有参数，可直接用于前端调起支付
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
        //	赋值：
        result.put("timeStamp", response.getTimeStamp()); // 时间戳
        result.put("nonceStr", response.getNonceStr());   // 随机字符串
        result.put("package", response.getPackageVal());  // 订单详情扩展字符串
        result.put("signType", response.getSignType());   // 签名方式
        result.put("paySign", response.getPaySign());     // 签名
        //	返回map集合
        return result;
    }

    /**
     * 查询支付状态
     *
     * @param orderNo
     * @return
     */
    @Override
    public Transaction queryPayStatus(String orderNo) {
        QueryOrderByOutTradeNoRequest outTradeNoRequest = new QueryOrderByOutTradeNoRequest();
        outTradeNoRequest.setMchid(wxPayV3Config.getMerchantId());
        outTradeNoRequest.setOutTradeNo(orderNo);
        try {
            // 创建service对象
            JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
            Transaction transaction = service.queryOrderByOutTradeNo(outTradeNoRequest);
            System.out.println(transaction.getTradeState());
            return transaction;
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
        }
        return null;
    }

    /**
     * 微信支付异步通知接口
     *
     * @param request
     * @return
     */
    @Override
    public Transaction wxNotify(HttpServletRequest request) {
        // 从请求头中获取数据
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
        String wechatSignature = request.getHeader("Wechatpay-Signature");
        String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
        String requestBody = PayUtil.readData(request);

        // 构造请求参数
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(wechatpayNonce)
                .signature(wechatSignature)
                .timestamp(wechatTimestamp)
                .body(requestBody)
                .build();
        // 初始化解析器
        NotificationParser parser = new NotificationParser(config);
        try {
            // 以支付通知回调为例，验签、解密并转换成 Transaction
            Transaction transaction = parser.parse(requestParam, Transaction.class);
        } catch (ValidationException e) {
            // 签名验证失败，返回 401 UNAUTHORIZED 状态码
            log.error("sign verification failed", e);
        }
        // 默认返回数据
        return null;
    }

    /**
     * 支付测试接口
     *
     * @param paymentType
     * @param orderNo
     * @param userId
     * @return
     */
//    @Override
//    public Map<String, Object> createNative(String paymentType, String orderNo, Long userId) {
//        try {
//            //保存支付记录
//            PaymentInfo paymentInfo = paymentInfoService.savePaymentInfo(paymentType, orderNo, userId, );
//
//            // 构建service
//            NativePayService service = new NativePayService.Builder().config(rsaAutoCertificateConfig).build();
//            // request.setXxx(val)设置所需参数，具体参数可见Request定义
//            com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest request = new com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest();
//            com.wechat.pay.java.service.payments.nativepay.model.Amount amount = new com.wechat.pay.java.service.payments.nativepay.model.Amount();
//            amount.setTotal(1);
//            request.setAmount(amount);
//            request.setAppid(wxPayV3Config.getAppid());
//            request.setMchid(wxPayV3Config.getMerchantId());
//            request.setDescription(paymentInfo.getContent());
//            request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
//            request.setOutTradeNo(paymentInfo.getOrderNo());
//
//            // 调用下单方法，得到应答
//            com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse response = service.prepay(request);
//            // 使用微信扫描 code_url 对应的二维码，即可体验Native支付
//            System.out.println(response.getCodeUrl());
//
//            Map result = new HashMap<>();
//            result.put("codeUrl", response.getCodeUrl());
//            return result;
//        } catch (ServiceException e) {
//            e.printStackTrace();
//            throw new GuiguException(201, e.getErrorMessage());
//        } catch (IllegalArgumentException e) {
//            e.printStackTrace();
//            throw new GuiguException(201, "订单号不存在");
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new GuiguException(201, "微信下单异常");
//        }
//    }

}
